
module arbiter2to1(
    input                       i_clk                                   ,
    input                       i_rst                                   ,
    input                       s_axis_tvalid_0                         ,
    input   [7 : 0]             s_axis_tdata_0                          ,
    output                      s_axis_tready_0                         ,
    input                       s_axis_tlast_0                          ,
    input   [64: 0]             s_axis_tuser_0                          ,
    input                       s_axis_tvalid_1                         ,
    input   [7 : 0]             s_axis_tdata_1                          ,
    output                      s_axis_tready_1                         ,
    input                       s_axis_tlast_1                          ,
    input   [64: 0]             s_axis_tuser_1                          ,
    output                      m_axis_tvalid                           ,
    output  [7 : 0]             m_axis_tdata                            ,
    input                       m_axis_tready                           ,
    output                      m_axis_tlast                            ,
    output  [64: 0]             m_axis_tuser                            
);

    logic   [7 : 0]             axis_tx0_data                           ;
    logic   [64: 0]             axis_tx0_user                           ;
    logic                       axis_tx0_last                           ;
    logic                       axis_tx0_valid                          ;
    logic                       axis_tx0_ready                          ;
    logic   [7 : 0]             axis_tx1_data                           ;
    logic   [64: 0]             axis_tx1_user                           ;
    logic                       axis_tx1_last                           ;
    logic                       axis_tx1_valid                          ;
    logic                       axis_tx1_ready                          ;
    logic   [7 : 0]             axis_tx_data                            ;
    logic   [64: 0]             axis_tx_user                            ;
    logic                       axis_tx_last                            ;
    logic                       axis_tx_valid                           ;
    logic                       fifo_tx0_rden                           ;
    logic                       fifo_tx1_rden                           ;
    logic   [64: 0]             tx0_info                                ;
    logic   [64: 0]             tx1_info                                ;
    logic   [15: 0]             txcnt                                   ;
    logic   [7 : 0]             fifo_tx0_rddata                         ;
    logic                       fifo_tx0_full                           ;
    logic                       fifo_tx0_empty                          ;
    logic   [7 : 0]             fifo_tx1_rddata                         ;
    logic                       fifo_tx1_full                           ;
    logic                       fifo_tx1_empty                          ;
    logic                       tx0_handshake                           ;
    logic                       tx1_handshake                           ;
    logic   [1 : 0]             c_state                                 ;
    logic   [1 : 0]             n_state                                 ;

    // ila128_bit ila128_bit_arbit(
    //     .clk    ( i_clk),
    //     .probe0 ( {
    //             c_state                                 ,
    //             fifo_tx0_rden                           ,
    //             fifo_tx1_rden                           ,
    //             txcnt                                   ,
    //             fifo_tx0_rddata                         ,
    //             fifo_tx0_full                           ,
    //             fifo_tx0_empty                          ,
    //             fifo_tx1_rddata                         ,
    //             fifo_tx1_full                           ,
    //             fifo_tx1_empty                          ,
    //             tx0_info[23:0]                          ,
    //             tx1_info[23:0]                          ,
    //             s_axis_tvalid_0                         ,
    //             s_axis_tdata_0                          ,
    //             s_axis_tready_0                         ,
    //             s_axis_tlast_0                          ,
    //             s_axis_tvalid_1                         ,
    //             s_axis_tdata_1                          ,
    //             s_axis_tready_1                         ,
    //             s_axis_tlast_1                          ,
    //             m_axis_tvalid                           ,
    //             m_axis_tdata                            ,
    //             m_axis_tready                           ,
    //             m_axis_tlast                            

                  
    //               })

    // );

    localparam  ST_IDLE = 0;
    localparam  ST_ARBIT = 1;
    localparam  ST_CHNL0 = 2;
    localparam  ST_CHNL1 = 3;

    assign s_axis_tready_0 = axis_tx0_ready;
    assign s_axis_tready_1 = axis_tx1_ready;
    assign m_axis_tdata = axis_tx_data;
    assign m_axis_tuser = axis_tx_user;
    assign m_axis_tlast = axis_tx_last;
    assign m_axis_tvalid = axis_tx_valid;

    always_ff @(posedge i_clk) begin
        if(i_rst)
            c_state <= ST_IDLE;
        else 
            c_state <= n_state;
    end

    always_comb begin 
        if(i_rst)
            n_state = ST_IDLE;
        else  
            case (c_state)
                ST_IDLE : begin
                    if(m_axis_tready)
                        n_state = ST_ARBIT;
                    else  
                        n_state = ST_IDLE;
                end

                ST_ARBIT : begin
                    if(!fifo_tx0_empty) 
                        n_state = ST_CHNL0;
                    else if(!fifo_tx1_empty)
                        n_state = ST_CHNL1;
                    else  
                        n_state = ST_ARBIT;
                end

                ST_CHNL0 : begin
                    if(fifo_tx0_empty)
                        n_state = ST_IDLE;
                    else  
                        n_state = ST_CHNL0;
                end

                ST_CHNL1 : begin
                    if(fifo_tx1_empty)
                        n_state = ST_IDLE;
                    else  
                        n_state = ST_CHNL1;
                end
            endcase
        
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            tx0_handshake <= 0;
        else 
            tx0_handshake <= s_axis_tvalid_0 & s_axis_tready_0;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            tx1_handshake <= 0;
        else 
            tx1_handshake <= s_axis_tvalid_1 & s_axis_tready_1;
    end 

    always_ff @(posedge i_clk) begin
        if(i_rst) begin
            axis_tx0_data  <= 'd0;
            axis_tx0_user  <= 'd0;
            axis_tx0_last  <= 'd0;
            axis_tx0_valid <= 'd0;
            axis_tx1_data  <= 'd0;
            axis_tx1_user  <= 'd0;
            axis_tx1_last  <= 'd0;
            axis_tx1_valid <= 'd0;
        end 
        else begin
            axis_tx0_data  <= s_axis_tdata_0 ;
            axis_tx0_user  <= s_axis_tuser_0 ;
            axis_tx0_last  <= s_axis_tlast_0 ;
            axis_tx0_valid <= s_axis_tvalid_0;
            axis_tx1_data  <= s_axis_tdata_1 ;
            axis_tx1_user  <= s_axis_tuser_1 ;
            axis_tx1_last  <= s_axis_tlast_1 ;
            axis_tx1_valid <= s_axis_tvalid_1;
        end
    end

    always_ff @(posedge i_clk) begin
        if(i_rst) 
            axis_tx0_ready <= 0;
        else if(s_axis_tvalid_0 & s_axis_tlast_0)
            axis_tx0_ready <= 0;
        else if(fifo_tx0_empty & !axis_tx_valid & m_axis_tready)
            axis_tx0_ready <= 1;
        else 
            axis_tx0_ready <= axis_tx0_ready;     
    end

    always_ff @(posedge i_clk) begin
        if(i_rst) 
            axis_tx1_ready <= 0;
        else if(s_axis_tvalid_1 & s_axis_tlast_1)
            axis_tx1_ready <= 0;
        else if(fifo_tx1_empty & !axis_tx_valid & m_axis_tready)
            axis_tx1_ready <= 1;
        else 
            axis_tx1_ready <= axis_tx1_ready;     
    end


    sfifo_8x2048 sfifo_8x2048_inst0 (
        .clk                  ( i_clk               ), 
        .srst                 ( i_rst               ), 
        .din                  ( axis_tx0_data       ),  
        .wr_en                ( tx0_handshake       ),  
        .rd_en                ( fifo_tx0_rden       ), 
        .dout                 ( fifo_tx0_rddata     ), 
        .full                 ( fifo_tx0_full       ), 
        .empty                ( fifo_tx0_empty      )  
    );

    sfifo_8x2048 sfifo_8x2048_inst1 (
        .clk                  ( i_clk               ),  
        .srst                 ( i_rst               ), 
        .din                  ( axis_tx1_data       ),  
        .wr_en                ( tx1_handshake       ),  
        .rd_en                ( fifo_tx1_rden       ), 
        .dout                 ( fifo_tx1_rddata     ), 
        .full                 ( fifo_tx1_full       ), 
        .empty                ( fifo_tx1_empty      )  
    );

    

    always_ff @(posedge i_clk) begin
        if(i_rst) 
            tx0_info <= 'd0;
        else if(c_state == ST_ARBIT)
            tx0_info <= s_axis_tuser_0;
        else 
            tx0_info <= tx0_info;     
    end

    always_ff @(posedge i_clk) begin
        if(i_rst) 
            tx1_info <= 'd0;
        else if(c_state == ST_ARBIT)
            tx1_info <= s_axis_tuser_1;
        else 
            tx1_info <= tx1_info;     
    end


    always_ff @(posedge i_clk) begin
        if(i_rst)
            txcnt <= 0;
        else if(c_state == ST_CHNL0 && txcnt == tx0_info[15:0] - 1)
            txcnt <= 0;
        else if(c_state == ST_CHNL1 && txcnt == tx1_info[15:0] - 1)
            txcnt <= 0;
        else if(fifo_tx0_rden | fifo_tx1_rden)
            txcnt <= txcnt + 1;
        else        
            txcnt <= txcnt;  
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            fifo_tx0_rden <= 0;
        else if(fifo_tx0_rden && c_state == ST_CHNL0 && txcnt == tx0_info[15:0] - 1)
            fifo_tx0_rden <= 0;
        else if(m_axis_tready && !axis_tx_valid  && c_state == ST_CHNL0 )
            fifo_tx0_rden <= 1;
        else    
            fifo_tx0_rden <= fifo_tx0_rden; 
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            fifo_tx1_rden <= 0;
        else if(fifo_tx1_rden && c_state == ST_CHNL1 && txcnt == tx1_info[15:0] - 1)
            fifo_tx1_rden <= 0;
        else if(m_axis_tready && !axis_tx_valid && c_state == ST_CHNL1)
            fifo_tx1_rden <= 1;
        else    
            fifo_tx1_rden <= fifo_tx1_rden; 
    end

    always_ff @(posedge i_clk) begin
        if(i_rst) begin
            axis_tx_data  <= 0;
            axis_tx_user  <= 0;
            axis_tx_valid <= 0;
        end 
        else if(c_state == ST_CHNL0)begin
            axis_tx_data  <= fifo_tx0_rddata;
            axis_tx_user  <= tx0_info;
            axis_tx_valid <= fifo_tx0_rden;
           
        end
        else if(c_state == ST_CHNL1)begin
            axis_tx_data  <= fifo_tx1_rddata;
            axis_tx_user  <= tx1_info;
            axis_tx_valid <= fifo_tx1_rden;
           
        end
        else begin
            axis_tx_data  <= axis_tx_data;
            axis_tx_user  <= axis_tx_user;
            axis_tx_valid <= 0;
        end
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            axis_tx_last <= 0;
        else if(c_state == ST_CHNL0 && txcnt == tx0_info[15:0] - 1)
            axis_tx_last <= 1;
        else if(c_state == ST_CHNL1 && txcnt == tx1_info[15:0] - 1)
            axis_tx_last <= 1;
        else        
            axis_tx_last <= 0;
    end     





endmodule